package com.coder4j.starter.mybatis;

import com.coder4j.starter.mybatis.provider.*;
import com.coder4j.starter.mybatis.provider.BaseDeleteProvider;
import com.coder4j.starter.mybatis.provider.BaseInsertProvider;
import com.coder4j.starter.mybatis.provider.BaseSelectProvider;
import com.coder4j.starter.mybatis.provider.BaseUpdateProvider;
import com.coder4j.starter.tools.util.ListUtils;
import com.coder4j.starter.tools.util.ReflectUtils;
import com.coder4j.starter.tools.util.StringUtils;
import com.coder4j.starter.tools.vo.BaseException;
import org.apache.ibatis.annotations.*;
import org.springframework.dao.DuplicateKeyException;

import java.util.*;

/**
 * 动态表名Mapper
 *
 * @param <T>
 * @author Keller
 * @date 2021-11-27 11:10:00
 */
public interface BaseMapper<T> {

    /**
     * 默认的字段模糊查询
     * @param fieldName 数据库字段名
     * @return
     */
    default String baseLikeCondition(String fieldName) {
        String javaFieldName = StringUtils.lineToHump(fieldName);
        //LIKE CONCAT('%', #{name}, '%')
        return " <if test = '" + javaFieldName + "!=null'> AND " + fieldName + " LIKE CONCAT('%', #{"+javaFieldName+"}, '%') </if>";
    }

    /**
     * 默认的等值查询
     * @param fieldName
     * @return
     */
    default String baseEqualsCondition(String fieldName) {
        String javaFieldName = StringUtils.lineToHump(fieldName);
        return " <if test = '" + javaFieldName + "!=null'> AND " + fieldName + "=#{" + javaFieldName + "} </if>";
    }


    default List<String> defaultCondition(){
     return new ArrayList<>();
    }

    default String defaultOrder(){
        return "id DESC";
    }

    /**
     * 获取表名，先查自定义的动态表名，没有的话查基础表名
     *
     * @param entity
     * @return
     */
    default String getTableName(T entity) {
        return SqlFieldReader.getTableName(entity);
    }

    /**
     * 插入数据
     *
     * @param entity
     * @return
     */
    default int baseInsert(T entity) {
        ProviderVO<T> providerVO = new ProviderVO<>(getTableName(entity), entity);
        return baseDoInsert(providerVO);
    }

    /**
     * 添加数据
     *
     * @param providerVO
     * @return 影响的行数
     * @throws DuplicateKeyException 当唯一字段重复插入时，会抛该异常
     */
    @InsertProvider(type = BaseInsertProvider.class, method = "insert")
    Integer baseDoInsert(ProviderVO providerVO) throws DuplicateKeyException;

    /**
     * 批量插入
     *
     * @param list
     * @return
     */
    default int baseInsertList(List<T> list) {
        T entity = list.get(0);
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        providerVO.setList(list);
        return baseDoInsertList(providerVO);
    }

    /**
     * 批量插入
     *
     * @param providerVO 实体对象列表
     * @return 影响的行数
     * @throws DuplicateKeyException
     */
    @InsertProvider(type = BaseInsertProvider.class, method = "insertList")
    Integer baseDoInsertList(ProviderVO<T> providerVO) throws DuplicateKeyException;

    default long baseInsertAndReturnKey(T entity) {
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        baseDoInsertAndReturnKey(providerVO);
        if (providerVO.getId() == null) {
            return -0;
        }
        if (providerVO.getId() instanceof Number) {
            Number id = (Number) providerVO.getId();
            return id.longValue();
        }
        return 0;
    }

    /**
     * 插入数据并返回自增的主键
     *
     * @param providerVO 实体对象
     * @return 影响的行数
     * @throws DuplicateKeyException 当唯一字段重复插入时，会抛该异常
     */
    @InsertProvider(type = BaseInsertProvider.class, method = "insert")
    @Options(useGeneratedKeys = true, keyProperty = Constant.ID, keyColumn = Constant.ID)
    Integer baseDoInsertAndReturnKey(ProviderVO<T> providerVO);

    default int baseDeleteById(T entity) {
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        providerVO.setId(ReflectUtils.getValue(entity, BaseEntityEnums.id.name()));
        return baseDoDeleteById(providerVO);
    }

    default int baseDeleteByIds(T entity, List ids) {
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        if (ListUtils.isEmpty(ids)) {
            return 0;
        }
        providerVO.setIdList(ids);
        return baseDoDeleteByIds(providerVO);
    }

    /**
     * 根据Id删除数据
     *
     * @param providerVO 实体对象
     * @return 影响的行数
     */
    @DeleteProvider(type = BaseDeleteProvider.class, method = "deleteById")
    Integer baseDoDeleteById(ProviderVO<T> providerVO);

    @DeleteProvider(type = BaseDeleteProvider.class, method = "deleteByIds")
    Integer baseDoDeleteByIds(ProviderVO<T> providerVO);

    default int baseUpdateByIds(T entity, boolean ignoreNull, List ids) {
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        providerVO.setIgnoreNull(ignoreNull);
        providerVO.setIdList(ids);
        return baseDoUpdateByIds(providerVO);
    }

    default int baseUpdateById(T entity) {
        Object id = ReflectUtils.getValue(entity, "id");
        if (id == null) {
            throw BaseException.error("id为空");
        }
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        providerVO.setIgnoreNull(true);
        providerVO.setId(id);
        return baseDoUpdateById(providerVO);
    }

    /**
     * 根据id 更新数据
     *
     * @param providerVO 实体对象
     * @return 影响的行数
     */
    @UpdateProvider(type = BaseUpdateProvider.class, method = "updateById")
    Integer baseDoUpdateById(ProviderVO<T> providerVO);

    @UpdateProvider(type = BaseUpdateProvider.class, method = "updateByIds")
    Integer baseDoUpdateByIds(ProviderVO<T> providerVO);


    default T baseSelectById(T entity) {
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        providerVO.setId(ReflectUtils.getValue(entity, "id"));
        return baseDoSelectById(providerVO);
    }

    /**
     * 根据Id 查找数据
     *
     * @param providerVO 实体对象
     * @return 查询结果
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "selectById")
    T baseDoSelectById(ProviderVO<T> providerVO);

    default List<T> baseSelectByIdList(T entity, List idList) {
        String tableName = getTableName(entity);
        ProviderVO<T> providerVO = new ProviderVO<>(tableName, entity);
        List<Object> list = new ArrayList<>();
        for (Object object : idList) {
            list.add(object);
        }
        providerVO.setIdList(list);
        return baseDoSelectByIdList(providerVO);
    }

    /**
     * 根据Id 查找数据
     *
     * @param providerVO 实体对象
     * @return 查询结果
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "selectByIds")
    List<T> baseDoSelectByIdList(ProviderVO<T> providerVO);

    default <K extends BaseQuery<T>> List<T> baseSelectList(K query) {
        initQuery(query);
        return baseDoSelectList(query);
    }

    /**
     * 查询列表，可指定查询条件
     *
     * @param query 查询对象
     * @return 查询结果
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "selectList")
    <K extends BaseQuery<T>> List<T> baseDoSelectList(K query);


    default <K extends BaseQuery<T>> List<T> baseSelectPageList(K query) {
        initQuery(query);
        return baseDoSelectPageList(query);
    }

    /**
     * 分页查询，可指定查询条件
     *
     * @param query 查询对象
     * @return 查询结果
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "selectPageList")
    <K extends BaseQuery<T>> List<T> baseDoSelectPageList(K query);

    /**
     * 分页查询
     *
     * @param query 查询对象
     * @return DynamicPage 包含查询结果、分页参数、数据总量等
     */
    default <K extends BaseQuery<T>> BasePage<T> baseSelectPage(K query) {
        initQuery(query);
        // 查询出的数据
        List<T> list = baseDoSelectPageList(query);

        // 数据总数
        Integer count = baseDoSelectCount(query);

        BasePage<T> page = new BasePage<>();
        page.initByQuery(query, count);

        page.setDataList(list);

        return page;
    }

    default <K extends BaseQuery<T>> int baseSelectCount(K query) {
        initQuery(query);
        return baseDoSelectCount(query);
    }

    /**
     * 根据条件查询记录总数
     *
     * @param query 查询对象
     * @return 查询结果
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "selectCount")
    <K extends BaseQuery<T>> int baseDoSelectCount(K query);

    /**
     * 初始化 query ，组装表名，过滤 空值
     *
     * @param query
     * @param <K>
     */
    default <K extends BaseQuery<T>> void initQuery(K query) {
        T entity = query.getEntityInstance();
        String tableName = getTableName(entity);
        query.setTableName(tableName);

        query.setDefaultAliasTableName(tableName + " tbl ");

        if(query.getDefaultCondition() == null && ListUtils.notEmpty(defaultCondition())){
            query.setDefaultCondition(String.join("",defaultCondition()));
        }
        query.setDefaultOrder(defaultOrder());

        //将查询条件中，字符串类型的字段，包含 ""、" " 等空值的字段，全部替换成 null
        ReflectUtils.filterBlank(query);
    }
}
